import * as PackageManager from '@expo/package-manager';
import spawnAsync from '@expo/spawn-async';
import path from 'path';
import semver from 'semver';

/**
 * Install a node package non-interactively
 *
 * @param projectRoot target project root folder
 * @param pkg package name
 */
async function installPackageNonInteractiveAsync(projectRoot: string, pkg: string) {
  const manager = PackageManager.createForProject(projectRoot, { silent: false });

  if (manager.name === 'yarn') {
    const version = await manager.versionAsync();
    if (semver.major(version) === 1) {
      return manager.addAsync([pkg, '--non-interactive']);
    }
  }

  return manager.addAsync([pkg]);
}

export async function installBabelPresetExpoNonInteractiveAsync(projectRoot: string) {
  await spawnAsync('npx', ['expo', 'install', '--dev', 'babel-preset-expo'], {
    cwd: projectRoot,
  });
}

/**
 * Install the `expo` package
 *
 * @param projectRoot target project root folder
 * @param sdkVersion expo sdk version
 */
export async function installExpoPackageAsync(projectRoot: string, sdkVersion: string) {
  try {
    // First try to install from released versions, e.g. `expo@~45.0.0`
    await installPackageNonInteractiveAsync(projectRoot, `expo@${sdkVersion}`);
    return;
  } catch {}

  // Fallback to install from prerelease versions,
  // e.g. `expo@>=45.0.0-0 <46.0.0`, this will cover prerelease version for beta testing.
  const majorVersion = semver.minVersion(sdkVersion)?.major;
  if (!majorVersion) {
    throw new Error('Invalid SDK version');
  }
  await installPackageNonInteractiveAsync(
    projectRoot,
    `expo@>=${majorVersion}.0.0-0 <${majorVersion + 1}.0.0`
  );
}

/**
 * Running `pod install` for the target project
 *
 * @param projectRoot target project root folder
 */
export async function installPodsAsync(projectRoot: string) {
  const podPackageManager = new PackageManager.CocoaPodsPackageManager({
    cwd: path.join(projectRoot, 'ios'),
  });
  await podPackageManager.installAsync();
}
